#pragma once
//Common.h用来存放共同文件
#include<iostream>
#include<vector>
#include<time.h>
#include<assert.h>
#include<thread>
#include<mutex>
#include <stdio.h> 
#include<algorithm>
#include <sys/mman.h>  // 包含 mmap 和 munmap 声明  
#include <fcntl.h>     // 包含 O_* 常量  
#include <unistd.h>    // 包含 sysconf 和 close  
#include <stdexcept>   // 包含 std::bad_alloc  
#include <cstddef>     // 包含 size_t 


static const size_t MAX_BYTES = 256 * 1024;
static const size_t NFREELIST = 208;
static const size_t NSPANLIST = 129;
static const size_t PAGE_SHIFT = 13;

#if defined(__x86_64__) || defined(__aarch64__) // 检查是否为64位架构  
    typedef unsigned long long Page_Id;
#elif defined(__i386__) || defined(__arm__) // 检查是否为常见的32位架构
    typedef size_t Page_Id;
#endif

//在堆上申请空间
inline static void* SystemAlloc(size_t kpage)  
{  
    void* ptr = nullptr;  
  
#if defined(__i386__) || defined(__arm__) || defined(__linux__)  
    // Linux下使用mmap进行内存分配  
    // MAP_ANONYMOUS | MAP_PRIVATE 表示创建一个匿名、私有的内存映射  
    // 0 表示不使用文件或设备  
    // kpage * PAGE_SHIFT 是要映射的内存大小  
    // PROT_READ | PROT_WRITE 表示映射区域可读可写  
    // -1 和 0 分别作为 fd 和 offset，对于匿名映射来说这两个参数是无关紧要的  
    ptr = mmap(0, kpage * PAGE_SHIFT, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);  
  
    if (ptr == MAP_FAILED) {  
        // mmap失败时返回MAP_FAILED（通常是(void*)-1），抛出bad_alloc异常  
        throw std::bad_alloc();  
    }  
#else  
    // 其他平台可以留空或添加特定平台的处理  
#endif  
  
    return ptr;  
}


void*& ListNext(void* obj)
{
    return *(void**)obj;
}

//自由链表，用来存储已经分配过一次后的内存
class FreeList
{
public:
    void push(void* obj)
    {
        assert(obj);
        ListNext(obj) = _freelist;
        _freelist = obj;
    }

    void pushrange(void* start,void* end)
    {
        ListNext(end) = _freelist; 
        _freelist = start;
    }

    void* pop()
    {
        assert(_freelist);
        void* obj = _freelist;
        _freelist = obj; 
    }

    bool Empty()
    {
        return _freelist == nullptr;
    }

    size_t &MaxSize()
    {
        return _MaxSize;
    }
private:
    size_t _MaxSize = 1;
    void* _freelist = nullptr;
};

//用来对齐分配内存时的关键字以及计算哈希桶中所在位置
class Sizeclass
{
public:
    static inline size_t _Roundup(size_t size,size_t align_num)
    {
        return (size + align_num - 1) & ~(size/align_num);
    }

    static inline size_t Roundup(size_t size)
    {
        if(size <= 128)
        {
            _Roundup(size,8);
        }
        else if(size <= 1024)
        {
            _Roundup(size,16);
        }
        else if(size <= 8 * 1024)
        {
            _Roundup(size,128);
        }
        else if(size <= 64 * 1024)
        {
            _Roundup(size,1024);
        }
        else if(size <= 256 * 1024)
        {
            _Roundup(size,8 * 1024);
        }
        else
        {
            return -1;
        }
    }

    static inline size_t _index(size_t bytes,size_t align_shift)
    {
        return ((bytes + (1 << align_shift) - 1) >> align_shift) - 1;
    }

    static inline size_t Index(size_t bytes)
    {
        assert(bytes <= MAX_BYTES);
        static int group[] = {16,56,56,56};

        if(bytes <= 128)
        {
            return _index(bytes,3);
        }
        else if(bytes <= 1024)
        {
            return _index(bytes - 128,4) + group[0];
        }
        else if(bytes <= 8 * 1024)
        {
            return _index(bytes - 1024,7) + group[1] + group[0];
        }
        else if(bytes <= 64 * 1024)
        {
            return _index(bytes - 8 * 1024,10) + group[2] + group[1];
        }
        else if(bytes <= 256 * 1024)
        {
            return _index(bytes - 64 * 1024,18) + group[3] + group[2];
        }
        else
        {
            assert(false);
            return -1;
        }
    }

    //一次thread cache 从中心缓存中获取多少个
    static size_t NumMoiveSize(size_t size)
    {
        assert(size > 0);
        
        if(size == 0)
        {
            return 0;
        }
        int num = MAX_BYTES/size;
        if(num < 2)num = 2;
        if(num > 512) num = 512;
        return num; 
    }

    static size_t NumMovePage(size_t size)
    {
        size_t num = NumMoiveSize(size);
        size_t nPage = num * size;

        nPage >>=PAGE_SHIFT;
        if(nPage == 0)
            nPage = 1;
        return nPage;
    }
};

struct Span
{
    size_t Page_Id = 0; //页号
    size_t  _n = 0; //页的数量

    Span* next = nullptr;   //双向链表的结构
    Span* prev = nullptr;

    size_t count = 0;   //自由链表中内存的数量
    void* _freelist = nullptr;//Page的自由链表
};

class SpanList
{
public:
    SpanList()
    {
       _head = new Span;
       _head->next = _head;
       _head->prev = _head; 
    }

    Span Pushfront(Span* span)
    {
        Insert(Begin(),span);
    }

    Span* Popfront()
    {
        Span* front = _head->next;
        Erase(front);
        return front;
    }

    Span* Begin()
    {
        return _head->next;
    }

    Span* End()
    {
        return _head;
    }

    void Insert(Span* pos,Span* newSpan)
    {
        assert(pos);
        assert(newSpan);
        Span* prev = pos->prev;

        prev->next = newSpan;
        newSpan->next = pos;
        pos->prev = newSpan;
        newSpan->prev = prev;
    }
    void Erase(Span* pos)
    {
        assert(pos);
        Span* prev = pos->prev;
        Span* next = pos->next;

        prev->next = next;
        next->prev = prev; 
    }

    bool Empty()
    {
        return _head->next == _head;
    }
private:
    Span* _head = nullptr;
    //Span* _head;
public:
    std::mutex mtx;
};